iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
Modern Web

網頁技術探索:30天的前端學習系列 第 21

Day21 JS function 的語法作用域 Lexical Scope、執行緒與同步、非同步

  • 分享至 

  • xImage
  •  

JavaScript 是使用語法作用域的程式語言

下方有一個具名函式為 peopleName,裡面有一個變數並賦予其值,確認結果下一個 console.log();,並且執行這個函式,結果會得到預期的答案。

function peopleName() {
  var boy = "男生";
  console.log(boy); //男生
}
peopleName();

但如果改成這樣,結果就讀不到變數了,

function peopleName() {
  var boy = "男生";
}
peopleName();
console.log(boy); //boy is not defined

原因是 JS 是語法作用域的程式語言,要運行其中內容,要在 function 的大括號內才能運行,離開大括號就無法運行。
https://ithelp.ithome.com.tw/upload/images/20251005/20178516jLdtuzQA5M.png

靜態作用域

JS 是一個直譯式語言,語法作用域也稱靜態作用域,在語法解析時就已經確定作用域,也就是說當我在寫函式的過程中已經確認靜態作用域已經生成。變數的作用域在語法解析時,就已經確定作用域,且不會再改變。

動態作用域

動態作用域的意思就是當變數的作用域調用函式的時候,才會生成。

函式運行方式

函式的作用域基本上是各自獨立的,但倘若今天內部需要一個特定的變數,但函式內部自己沒有這個特定變數時,就會向外查找是否能在全域中找到變數,所以函式的找尋變數的方式式向外查找的,倘若連全域都找不到特定要使用的變數,就會出現 ReferenceError: variable is not defined 的警告訊息。

var name = Tim;

function myName() {
...
}

function urName() {
...
}
靜態作用域中函式的運作方式

答案會是什麼?

var value = 1;

function fn1() {
  console.log(value);
}

function fn2() {
  var value = 2;
  fn1();
}
fn2();

答案是 1。

原因:

在全域命名一個變數為 1。
執行 fn2();,裡面重新宣告變數為 2,並且再執行 fn1();。
但因為語法作用域的關係, var value = 2; 只會在 fn2(); 裡面取得。
後又在 fn2(); 內執行 fn1();。
而 fn1(); 是直接向外查找特定變數值。
所以找到了全域的變數,故答案為 1 。

動態作用域中函式的運作方式

答案會是什麼?

var value = 1;

function fn1() {
  console.log(value);
}

function fn2() {
  var value = 2;
  fn1();
}
fn2();

因為動態作用域的是在函式調用時才會執行,所以在這個作用域下函式調用會找到的值是 2。

var value = 2; //動態作用域會找上一層的變數
fn1();

結論:

但因為 JavaScript 是靜態作用域的語言,所以這題答案會是 1。

執行緒與同步、非同步

有單執行緒就有多執行緒,多執行緒就是可以在同個時間執行多個函式,可是 JavaScript 是單執行緒的程式語言,所以若給予一個以上的函式,會分開且按照順序執行,
例如:

function A() {
  console.log('work A');
}

function B() {
  console.log('work B');
}

function C() {
  console.log('work C');
}

function D() {
  A();
  B();
  C();
}
D();

但 JS 有同步與非同步(Async)可以使用。而單執行緒是對於系統的執行,非同步是對於程式語言本身來執行,上方例子就是一個同步的範例,會按照給予的順序來進行,不會 A(); 執行完就去執行 C();,非同步的執行就是把原本要執行的內容往後放,這裡的現象稱為事件佇列(Event Queue)。

事件佇列 Event Queue

倘若下方有個函式,當中有一個非同步事件,非同步事件就會先移到事件佇列中,然後等到其他含是依序完成後,詳細解釋就是說當執行到 school(),時,setTimout()會先跳過不執行,等到 Go() 執行完後,才會執行 setTimeout 的事件佇列。

function toilet() {
  console.log('上廁所');
}

function Eat() {
  console.log('吃早餐');
}

function school(doSomething) {
  console.log('上學');
  setTimeout(function () {
    console.log('揹書包' + doSomething);
  }, 1000);
}

function Go() {
  toilet();
  Eat();
  school();
}
Go();

監聽事件的非同步
很常使用的就是點擊事件這個監聽,原生的 JS 會寫綁定 DOM 元素,並給予監聽,最後會給個 false 或 true,預設是給 false ,原因是要先點擊後才會執行事件。


上一篇
Day20 JS 認識與使用函式 function及在函式加入參數
下一篇
DAY22 js全域變數與區域變數
系列文
網頁技術探索:30天的前端學習24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言